package com.k.kc.cryptojava;

import com.k.kc.util.ByteUtils;
import com.k.kc.util.FileUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.List;

/**
 * AES标准所要求的密钥大小应为128、192或256位，分别为16、24和32字节。
 * 测试
 * http://tool.chacuo.net/cryptdes
 * Created by 170623910 on 2021/8/31.
 * @author 170623910
 */
public class AESUtils {

    private static final String ALGORITHM_TYPE = "AES";

    /**
     *  加密算法-工作模式-填充模式
     *  AES/ECB/PKCS5Padding
     *  AES/ECB/NoPadding
     */
    private static final String ENCRYPT_MODEL = "AES/ECB/NoPadding";

    /**
     * 偏移量  ECB 模式不需要偏移量
     */
    private static final String IV = "123";

    /**
     * 秘钥 16位
     */
    private String key = "1qaz2wsx3edc4rfv";

    private static Key genKey(byte[] key){
        return new SecretKeySpec(key, ALGORITHM_TYPE);
    }

    /**
     * 加密
     * @param key key
     * @param content input
     * @return out
     * @throws Exception e
     */
    private static byte[] encrypt(byte[] key, byte[] content) throws Exception {
        Cipher cipher = Cipher.getInstance(ENCRYPT_MODEL);
        cipher.init(Cipher.ENCRYPT_MODE, genKey(key));
        return cipher.doFinal(content);
    }

    /**
     * 解密
     * @param key key
     * @param content content
     * @return out
     * @throws Exception e
     */
    private static byte[] decrypt(byte[] key, byte[] content) throws Exception{
        Cipher cipher = Cipher.getInstance(ENCRYPT_MODEL);
        cipher.init(Cipher.DECRYPT_MODE, genKey(key));
        return cipher.doFinal(content);
    }


    // 加密 为Base64的密文
    public static String EncryptToBase64(String sSrc, String sKey) throws Exception {
        byte[] key = sKey.getBytes("utf-8");
        byte[] content = sSrc.getBytes("utf-8");
        byte[] encrypted = encrypt(key,content);
        //此处使用BASE64做转码功能，同时能起到2次加密的作用。
        return ByteUtils.toBase64(encrypted);
    }

    // 解密  从Base64的密文
    public static String DecryptFromBase64(String sSrc, String sKey) throws Exception {
        byte[] key = sKey.getBytes("utf-8");
        byte[] encrypted = ByteUtils.fromBase64(sSrc, StandardCharsets.UTF_8);
        byte[] decrypt = decrypt(key, encrypted);
        return new String(decrypt,"utf-8");
    }

    public static byte[] readFileToByte(String filePathname) throws IOException {
        byte[] b;
        try(FileInputStream fis = new FileInputStream(new File(filePathname));
            ByteArrayOutputStream bos = new ByteArrayOutputStream();){
            int i;
            while ((i = fis.read()) != -1){
                bos.write(i);
            }
            b = bos.toByteArray();
            fis.close();
            bos.close();
        }catch (Exception e){
            throw e;
        }
        return b;
    }
    private static byte[] charToByte(char[] chars){
        Charset cs = Charset.forName ("UTF-8");
        CharBuffer cb = CharBuffer.allocate (chars.length);
        cb.put (chars);
        cb.flip ();
        ByteBuffer bb = cs.encode (cb);
        return bb.array();
    }


    // ************************************************************************************************************
    // TEST
    // ************************************************************************************************************

    public static void main(String[] args) {
        testAES();
    }

    /**
     3721:Encrypt  :1f+4ym6OyTl0TryX97kxuA==
     1f+4ym6OyTl0TryX97kxuA==: Decrypt  :3721
     */
    public static void testAES() {
        String msg = "";//"{\"msg\":\"success\",\"code\":0,\"data\":[{\"name\":\"ops\",\"masterIp\":\"10.161.60.25\",\"masterPort\":12301,\"slaveIp\":\"10.161.60.25\",\"slavePort\":12301,\"updateTime\":\"2021-05-12 11:20:18\"},{\"name\":\"dss\",\"masterIp\":\"10.161.64.87\",\"masterPort\":44446,\"slaveIp\":\"10.161.64.87\",\"slavePort\":44446,\"updateTime\":\"2021-06-14 17:27:34\"},{\"name\":\"mcs\",\"masterIp\":\"10.161.42.148\",\"masterPort\":8071,\"slaveIp\":\"10.161.42.148\",\"slavePort\":8071,\"updateTime\":\"2021-06-14 17:28:03\"}]}";
        try {
            List<String> list = FileUtils.readLines("c:\\aes\\licenseKey",Charset.forName("utf-8"));
            for(String lineStr:list){
                msg += lineStr;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // AES标准所要求的密钥大小应为128、192或256位，分别为16、24和32字节。
        msg = "1234567890123456789012345678901234567890123456789012345678901234";
        String key = "1";//"1234567890123456";
        byte[] keybyte = key.getBytes(Charset.forName("utf-8"));
        System.out.println("秘钥 key 大小 :"+ keybyte.length + " Byte" + " "+keybyte.length *8 + " bit");
        String msgEncrypt = "";
        String msgDecrypt = "";
        try {
            msgEncrypt = AESUtils.EncryptToBase64(msg,key);
            System.out.println(msg+":Encrypt  :"+msgEncrypt);

            msgDecrypt = AESUtils.DecryptFromBase64(msgEncrypt,key);
            System.out.println(msgEncrypt+": Decrypt  :"+msgDecrypt);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
